package cn.twh.wall.service;

import cn.twh.wall.config.BeetlConfig;
import cn.twh.wall.constant.WallErrorConstants;
import cn.twh.wall.constant.WallMessageConstants;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.AllowAllMatcher;
import org.beetl.core.resource.CompositeResourceLoader;
import org.beetl.core.resource.FileResourceLoader;
import org.beetl.core.resource.StartsWithMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Map;

@Service
@Slf4j
@Data
public class BeetlHandle {

    private GroupTemplate groupTemplate;
    private final BeetlConfig beetlConfig;
    /**
     * 已创建过的dir目录
     */
    private HashSet<String> pkgCreated;

    private boolean initialized = false;

    @Autowired
    public BeetlHandle(BeetlConfig beetlConfig) {
        this.beetlConfig = beetlConfig;
    }

    public void init() {
        if (initialized) {
            return;
        }
        initialized = true;
        pkgCreated = new HashSet<>();
        log.info(WallMessageConstants.INIT_BEETL_START);
        // 构建文件加载器
        FileResourceLoader base = new FileResourceLoader(beetlConfig.getBasePath());
        FileResourceLoader comm = new FileResourceLoader(beetlConfig.getCommPath());
        FileResourceLoader item = new FileResourceLoader(beetlConfig.getItemPath());
        // 使用组合加载器
        CompositeResourceLoader resourceLoader = new CompositeResourceLoader();
        resourceLoader.addResourceLoader(new StartsWithMatcher("comm:"), comm);
        resourceLoader.addResourceLoader(new StartsWithMatcher("item:"), item);
        resourceLoader.addResourceLoader(new AllowAllMatcher(), base);
        // 使用默认配置
        Configuration cfg = null;
        try {
            cfg = Configuration.defaultConfiguration();
        } catch (IOException e) {
            throw new RuntimeException(WallMessageConstants.INIT_BEETL_FAILED);
        }
        // 构建Beetl核心类，建议使用单例方式构建
        groupTemplate = new GroupTemplate(resourceLoader, cfg);
        log.info(WallMessageConstants.INIT_BEETL_OVER);
    }

    public Template getTemplate(String key) {
        return groupTemplate.getTemplate(key);
    }

    public Template getTemplate() {
        return getTemplate(beetlConfig.getDefaultTemplate());
    }

    public GroupTemplate getGroupTemplate() {
        return groupTemplate;
    }

    /**
     * 创建目录结构并生成文件
     *
     * @param dir      目录
     * @param filename 文件名
     * @param body     文件内容
     */
    public void createFileAndDirectory(String dir, String filename, byte[] body) {
        // 存在该文件路径时不创建目录，不存在时创建相关目录
        if (!pkgCreated.contains(dir)) {
            File file = new File(dir);
            if (!file.exists() && !file.isDirectory()) {
                file.mkdirs();
                pkgCreated.add(dir);
            }
        }
        // 创建文件
        try (FileOutputStream fos = new FileOutputStream(new File(dir + "\\" + filename));
             ByteArrayInputStream dais = new ByteArrayInputStream(body)) {
            IOUtils.copy(dais, fos);
        } catch (Exception e) {
            log.error(WallErrorConstants.FILE_CREATE_ERROR, e);
            throw new RuntimeException(WallErrorConstants.FILE_CREATE_ERROR + filename);
        }
    }

    /**
     * 使用 默认模板 构建文件
     *
     * @param javaMap 配置map
     * @return java文件内容
     */
    public String genTemplateTargetString(Map<?, ?> javaMap) {
        return genTemplateTargetString(beetlConfig.getDefaultTemplate(), javaMap);
    }

    /**
     * 使用 templateId 对应的模板构建文件
     *
     * @param templateId 模板Id
     * @param javaMap    配置map
     * @return java文件内容
     */
    public String genTemplateTargetString(String templateId, Map<?, ?> javaMap) {
        // 获取模板
        Template template = getTemplate(templateId);
        template.binding(javaMap);
        // 渲染结果
        return template.render();
    }
}
